{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZrwVQsM9TiUw"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Probability Authors.\n",
        "\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\");"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "CpDUTVKYTowI"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\"); { display-mode: \"form\" }\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ltPJCG6pAUoc"
      },
      "source": [
        "# TFP Probabilistic Layers: Variational Auto Encoder\n",
        "\n",
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/probability/examples/Probabilistic_Layers_VAE\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />View on TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/probability/blob/master/tensorflow_probability/examples/jupyter_notebooks/Probabilistic_Layers_VAE.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/probability/blob/master/tensorflow_probability/examples/jupyter_notebooks/Probabilistic_Layers_VAE.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/probability/tensorflow_probability/examples/jupyter_notebooks/Probabilistic_Layers_VAE.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Download notebook</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WRVR-tGTR31S"
      },
      "source": [
        "In this example we show how to fit a Variational Autoencoder using TFP's \"probabilistic layers.\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uiR4-VOt9NFX"
      },
      "source": [
        "### Dependencies & Prerequisites\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kZ0MdF1j8WJf"
      },
      "outputs": [],
      "source": [
        "#@title Import { display-mode: \"form\" }\n",
        "\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "import tensorflow.compat.v2 as tf\n",
        "tf.enable_v2_behavior()\n",
        "\n",
        "import tensorflow_datasets as tfds\n",
        "import tensorflow_probability as tfp\n",
        "\n",
        "\n",
        "tfk = tf.keras\n",
        "tfkl = tf.keras.layers\n",
        "tfpl = tfp.layers\n",
        "tfd = tfp.distributions"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7nnwjUdVoWN2"
      },
      "source": [
        "### Make things Fast!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2CK9RaDcoYPG"
      },
      "source": [
        "Before we dive in, let's make sure we're using a GPU for this demo.  \n",
        "\n",
        "To do this, select \"Runtime\" -> \"Change runtime type\" -> \"Hardware accelerator\" -> \"GPU\".\n",
        "\n",
        "The following snippet will verify that we have access to a GPU."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qP_4Xr8vpA42"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "SUCCESS: Found GPU: /device:GPU:0\n"
          ]
        }
      ],
      "source": [
        "if tf.test.gpu_device_name() != '/device:GPU:0':\n",
        "  print('WARNING: GPU device not found.')\n",
        "else:\n",
        "  print('SUCCESS: Found GPU: {}'.format(tf.test.gpu_device_name()))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FJRBc_S0ppfE"
      },
      "source": [
        "Note: if for some reason you cannot access a GPU, this colab will still work. (Training will just take longer.)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N8Shtn_e99XC"
      },
      "source": [
        "### Load Dataset"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "daPl6ycN9cD3"
      },
      "outputs": [],
      "source": [
        "datasets, datasets_info = tfds.load(name='mnist',\n",
        "                                    with_info=True,\n",
        "                                    as_supervised=False)\n",
        "\n",
        "def _preprocess(sample):\n",
        "  image = tf.cast(sample['image'], tf.float32) / 255.  # Scale to unit interval.\n",
        "  image = image < tf.random.uniform(tf.shape(image))   # Randomly binarize.\n",
        "  return image, image\n",
        "\n",
        "train_dataset = (datasets['train']\n",
        "                 .map(_preprocess)\n",
        "                 .batch(256)\n",
        "                 .prefetch(tf.data.experimental.AUTOTUNE)\n",
        "                 .shuffle(int(10e3)))\n",
        "eval_dataset = (datasets['test']\n",
        "                .map(_preprocess)\n",
        "                .batch(256)\n",
        "                .prefetch(tf.data.experimental.AUTOTUNE))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZPKblOe58Hql"
      },
      "source": [
        "Note that _preprocess() above returns `image, image` rather than just `image` because Keras is set up for discriminative models with an (example, label) input format, i.e. $p_\\theta(y|x)$. Since the goal of the VAE is to recover the input x from x itself (i.e. $p_\\theta(x|x)$), the data pair is (example, example)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CI-VFyp8-BIa"
      },
      "source": [
        "### VAE Code Golf"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MKgRI5eoS2rx"
      },
      "source": [
        "#### Specify model."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rd3Voa64_Gtv"
      },
      "outputs": [],
      "source": [
        "input_shape = datasets_info.features['image'].shape\n",
        "encoded_size = 16\n",
        "base_depth = 32"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9d7Jbm66FN_u"
      },
      "outputs": [],
      "source": [
        "prior = tfd.Independent(tfd.Normal(loc=tf.zeros(encoded_size), scale=1),\n",
        "                        reinterpreted_batch_ndims=1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eRHjRtAL-e33"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/linalg/linear_operator_lower_triangular.py:158: calling LinearOperator.__init__ (from tensorflow.python.ops.linalg.linear_operator) with graph_parents is deprecated and will be removed in a future version.\n",
            "Instructions for updating:\n",
            "Do not pass `graph_parents`.  They will  no longer be used.\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/linalg/linear_operator_lower_triangular.py:158: calling LinearOperator.__init__ (from tensorflow.python.ops.linalg.linear_operator) with graph_parents is deprecated and will be removed in a future version.\n",
            "Instructions for updating:\n",
            "Do not pass `graph_parents`.  They will  no longer be used.\n"
          ]
        }
      ],
      "source": [
        "encoder = tfk.Sequential([\n",
        "    tfkl.InputLayer(input_shape=input_shape),\n",
        "    tfkl.Lambda(lambda x: tf.cast(x, tf.float32) - 0.5),\n",
        "    tfkl.Conv2D(base_depth, 5, strides=1,\n",
        "                padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2D(base_depth, 5, strides=2,\n",
        "                padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2D(2 * base_depth, 5, strides=1,\n",
        "                padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2D(2 * base_depth, 5, strides=2,\n",
        "                padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2D(4 * encoded_size, 7, strides=1,\n",
        "                padding='valid', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Flatten(),\n",
        "    tfkl.Dense(tfpl.MultivariateNormalTriL.params_size(encoded_size),\n",
        "               activation=None),\n",
        "    tfpl.MultivariateNormalTriL(\n",
        "        encoded_size,\n",
        "        activity_regularizer=tfpl.KLDivergenceRegularizer(prior)),\n",
        "])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "baP--pt6-ewK"
      },
      "outputs": [],
      "source": [
        "decoder = tfk.Sequential([\n",
        "    tfkl.InputLayer(input_shape=[encoded_size]),\n",
        "    tfkl.Reshape([1, 1, encoded_size]),\n",
        "    tfkl.Conv2DTranspose(2 * base_depth, 7, strides=1,\n",
        "                         padding='valid', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2DTranspose(2 * base_depth, 5, strides=1,\n",
        "                         padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2DTranspose(2 * base_depth, 5, strides=2,\n",
        "                         padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2DTranspose(base_depth, 5, strides=1,\n",
        "                         padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2DTranspose(base_depth, 5, strides=2,\n",
        "                         padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2DTranspose(base_depth, 5, strides=1,\n",
        "                         padding='same', activation=tf.nn.leaky_relu),\n",
        "    tfkl.Conv2D(filters=1, kernel_size=5, strides=1,\n",
        "                padding='same', activation=None),\n",
        "    tfkl.Flatten(),\n",
        "    tfpl.IndependentBernoulli(input_shape, tfd.Bernoulli.logits),\n",
        "])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7itugvZVLyWL"
      },
      "outputs": [],
      "source": [
        "vae = tfk.Model(inputs=encoder.inputs,\n",
        "                outputs=decoder(encoder.outputs[0]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-ckYuzfILkVb"
      },
      "source": [
        "#### Do inference."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "e7f1u-Ya-axQ"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Epoch 1/15\n",
            "235/235 [==============================] - 14s 61ms/step - loss: 206.5541 - val_loss: 163.1924\n",
            "Epoch 2/15\n",
            "235/235 [==============================] - 14s 59ms/step - loss: 151.1891 - val_loss: 143.6748\n",
            "Epoch 3/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 141.3275 - val_loss: 137.9188\n",
            "Epoch 4/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 136.7453 - val_loss: 133.2726\n",
            "Epoch 5/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 132.3803 - val_loss: 131.8343\n",
            "Epoch 6/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 129.2451 - val_loss: 127.1935\n",
            "Epoch 7/15\n",
            "235/235 [==============================] - 14s 59ms/step - loss: 126.0975 - val_loss: 123.6789\n",
            "Epoch 8/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 124.0565 - val_loss: 122.5058\n",
            "Epoch 9/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 122.9974 - val_loss: 121.9544\n",
            "Epoch 10/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 121.7349 - val_loss: 120.8735\n",
            "Epoch 11/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 121.0856 - val_loss: 120.1340\n",
            "Epoch 12/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 120.2232 - val_loss: 121.3554\n",
            "Epoch 13/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 119.8123 - val_loss: 119.2351\n",
            "Epoch 14/15\n",
            "235/235 [==============================] - 14s 58ms/step - loss: 119.2685 - val_loss: 118.2133\n",
            "Epoch 15/15\n",
            "235/235 [==============================] - 14s 59ms/step - loss: 118.8895 - val_loss: 119.4771\n"
          ]
        }
      ],
      "source": [
        "negloglik = lambda x, rv_x: -rv_x.log_prob(x)\n",
        "\n",
        "vae.compile(optimizer=tf.optimizers.Adam(learning_rate=1e-3),\n",
        "            loss=negloglik)\n",
        "\n",
        "_ = vae.fit(train_dataset,\n",
        "            epochs=15,\n",
        "            validation_data=eval_dataset)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hC4rNz9t_zpo"
      },
      "source": [
        "### Look Ma, No ~~Hands~~Tensors!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3ZqfOYMP_2p_"
      },
      "outputs": [],
      "source": [
        "# We'll just examine ten random digits.\n",
        "x = next(iter(eval_dataset))[0][:10]\n",
        "xhat = vae(x)\n",
        "assert isinstance(xhat, tfd.Distribution)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "MM7wW4S2OrBt"
      },
      "outputs": [],
      "source": [
        "#@title Image Plot Util\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "def display_imgs(x, y=None):\n",
        "  if not isinstance(x, (np.ndarray, np.generic)):\n",
        "    x = np.array(x)\n",
        "  plt.ioff()\n",
        "  n = x.shape[0]\n",
        "  fig, axs = plt.subplots(1, n, figsize=(n, 1))\n",
        "  if y is not None:\n",
        "    fig.suptitle(np.argmax(y, axis=1))\n",
        "  for i in range(n):\n",
        "    axs.flat[i].imshow(x[i].squeeze(), interpolation='none', cmap='gray')\n",
        "    axs.flat[i].axis('off')\n",
        "  plt.show()\n",
        "  plt.close()\n",
        "  plt.ion()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ow7rfh6YLLx1"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Originals:\n"
          ]
        },
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 720x72 with 10 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light",
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Decoded Random Samples:\n"
          ]
        },
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 720x72 with 10 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light",
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Decoded Modes:\n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAA9CAYAAACpzLMWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAEjklEQVR4nO3d25LqOAwFUJia//9l5qmru5hA7om0vdbroU9Ztgmy7CTP1+v1AABI9s/dDQAAOJuEBwCIJ+EBAOJJeACAeBIeACCehAcAiPfvzL93v2f9ueAzYqxvLsb0+B4PMXYgxvz4Hg8xdjAZowoPABBPwgMAxJPwAADx5s7wAMR7Pv+/5e+1O5BFhQcAiFe+wvN8Pq20gFNMVXbo5WcM/U709P4dPHMcVXgAgHhlKjzfVlpXZoBHWLpqrB4HJFLVyfA+jtUrPUfOu6oxrnX1d/HWhGdrsFW3udbG8/fzFeM5gsOgVJG2ENl6/ewS3zedktYz2lr1N7A6W1oAQLzLKzydMvOljoipQjlWNWa5Ttus3+Zn5XYfZc33s0N/7L3edK4sd7pGJf7WdafCAwDEK3No+cdUtl41U967cpz6+7sqPVX7uIIlfTP3mbtWoXPtWjvuVVfTn1Qdly3OOgvyo3JfdKrs/Phpn2trHZclPHvK6hUnzhEX0opxHSUhpq1zNiH2TypsvS6RlOg8Htlzak7HZOevtW1dMtad4p9y13y2pQUAxLuswrMnI+22ulkb6+v1mnymRPcsvrMtq8pu8zTRCKvjd1viqbSdvkbltu01+s0FV8SowgMAxCt3aJk6js64u65SlrS76jmDI9rQoXKVWtk5a9Xf4fxg5bbtlfYQzC5UeACAeOUrPNWy/CtXXHfvqY9+jqhzZYdfaeORFs8SKTFX+z272t3xl094pqRM/g7WJl13T+i91j63xly8X+Jhz+7foz32vJPw8eg75qO6crxsaQEA8cpWeDptFVRt1xpTt8b/NeKKs9McPENq/F0PjFZrD+dTvTqWCg8AEO/QCs+eldOIFYRqzr5V9e5D2N+Yf78S+uKIa0zl+TqSta8eqnyzxXu79pxXqhrjJxWuK4ckPHsPmc3pNrDdnZX4VBzHCl/CSlIOABvX71K3K7vZk5gnJORXt92WFgAQb3eFZ+1biROrOwmZ9pQjb0Wv3jejvv18iepjxzqjz+fq1lZ9Om9zXU2FBwCIt7nCs3av36riu8576h3ey/NJlz4+W8ex22PJnE2bG6mxjnDr9t6dkjtVaqsKDwAQ7/QHD1bK7o7wbWW49SxPWh9Vt3ScRlg5pq7654z0nRt1jBOlzNu75t0pCU/iweQ1lj4HwoXoWikXi6N86o9uc2/uKeFb/r8E6deXbguSs2/wqaZi+21pAQDxbnmXVvVMfAnvnsqWfKtn4sr/qIPzleNfUtFIeETEu6mKeeL1NXnuVqHCAwDE21zhWbuiSsw+j7wdO7F/qlu7p95dYmXnXcp1aUkcqWclp2IfYe5u1Sn+u9u6e0vr7gAqGOFp0qMZZUxS40yJa8+iqnsfzMXeLb6/7bV9dQ9bWgBAvFsOLaeTff+q1BffKnGV2nm0xAOeo1laHUicx2LqqWKMKjwAQDwVHg5TMaP/plt7jzZ6/F0ZN9hGhQcAiKfCA4NRIQBGJOGBcBIcAFtaAMAAnlZ/AEA6FR4AIJ6EBwCIJ+EBAOJJeACAeBIeACCehAcAiPcfihw+yJcq6IAAAAAASUVORK5CYII=\n",
            "text/plain": [
              "<Figure size 720x72 with 10 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light",
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Decoded Means:\n"
          ]
        },
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 720x72 with 10 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light",
            "tags": []
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "print('Originals:')\n",
        "display_imgs(x)\n",
        "\n",
        "print('Decoded Random Samples:')\n",
        "display_imgs(xhat.sample())\n",
        "\n",
        "print('Decoded Modes:')\n",
        "display_imgs(xhat.mode())\n",
        "\n",
        "print('Decoded Means:')\n",
        "display_imgs(xhat.mean())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "C3_5HPUCQpYO"
      },
      "outputs": [],
      "source": [
        "# Now, let's generate ten never-before-seen digits.\n",
        "z = prior.sample(10)\n",
        "xtilde = decoder(z)\n",
        "assert isinstance(xtilde, tfd.Distribution)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_jMPwz8r9pYX"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Randomly Generated Samples:\n"
          ]
        },
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 720x72 with 10 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light",
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Randomly Generated Modes:\n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAA9CAYAAACpzLMWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAEbElEQVR4nO3dy47rOAwFwHgw///LfReDYHLTieN3yKOqbacB0fKDoiR7+vn5uQEAJPvn2w0AADibhAcAiCfhAQDiSXgAgHgSHgAgnoQHAIj374e/d9+zPi34jRjr+xRjeny3mxg7EGN+fLebGDt4GaMKDwAQT8IDAMST8AAA8SQ8AEA8CQ8AEO/TLi0ONE2vF8cnf8D1MebkOIFrPd9P3V/4RIUHAIh3WoXnXTVjqZRsfclxmKYpJt67vf3f0T3mtL5Mk3i9jSb5/rI0ts7n8BH9tyX+UxKeuWDeNfL5f7o/PJIvyJEtTWDvKp+/r2Kp3N69Rrgmt9x7+Z7Rz8mrmdICAOKdUuHZMpK4/0+lbHCrhBj4LaVfU+IY1db+61J5nJNy7o5QXa1YbVThAQDi2ZZ+oeesNmW08ihx6/3akUrHfu3cP5907I9nCTGcJeHcTYjhnUqxlUl4Et6psPbBmDSNl2hr2blqv65tT8I1CZUlXlOVNxyZ0gIA4pWo8HRfTHfE4qzKWfGIRlhUeLuti8n7a653ZJWwc99Vq5bu1bkv5lTvJxUeACDe5RWexEWtr6TFs0RCVeSIGKqNcka55qA6lfzvUuEBAOKdXuFZMtrtmu1WG8mzXUJ1Cujh1Q7ItGdlxWpWiY+Hpi2GTIplic7JwpnTPVWPQdV2ca6KD6AlRpmSXfJOr+4bfL7NlBYAEO+0Cs+S7PMxW+32krOzprM6jcISp/T2HPeKx2NLmyrGwXHSKuodLT3+7343TVPJZ8WrqblK7VThAQDiffXFg48ZX8JcZZd28p8jKxmdqiKvRlyd2r9W1U99LNG57Xt9irlS5WCpo9q6dJHzN7w7ZytUFku8afl2m/+wZscTO90oCwk/qb5ge+7GWPWGyW9bdvHM/b7iPXXr+VgxlitVjX/JIuyr22xKCwCIV6bC82zUUm61LP3ZaP2xRvW+439VR8Vz1rZ1tHtox2UQo3k+J6+ukKvwAADxylZ47h7nrjuOyuZ0GnmlvQV0r059926k/6m/OsVIf3srUiPdf7pbsmHpjP5U4QEA4pWv8HSyNDNNGzmPNLLqvDttbxs7xEh/czt2l/yeXt719xnb2CU8G33a7pty0aYlZ1vMHYOq/cZvoy3iJdcoC7SPnt4ypQUAxCtf4emaya4ZRXaK61HXds9Z2m+Jsd+pgPSypb86nb+V3yp8tarPwz3turJvVXgAgHiHVniOfIlQh4x+65qASpn5VikxjNh30M2re22Xa/GINnd4Ht4d1dYz+vfQhOfVSbk3+A4n9dw3Qzq0f85zn3aP59mSpDUtZrKsTdw7n88d2/54j0l9Hi75btaa/z2LKS0AIN4pi5bXvoemata6R1pMafE8S49vjfTt26MugnWOf9fc8b/6m1JXqNh+FR4AIN5XtqVXzPyAvyVfp2mxpcUzGv13DRUeACCehAcAiCfhAQDiSXgAgHiTxVIAQDoVHgAgnoQHAIgn4QEA4kl4AIB4Eh4AIJ6EBwCI9wdSMSmwdJRt9wAAAABJRU5ErkJggg==\n",
            "text/plain": [
              "<Figure size 720x72 with 10 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light",
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Randomly Generated Means:\n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAA9CAYAAACpzLMWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAe8ElEQVR4nO2de5DVdfnHX3v2wtlluexyWbmsiFyUAEPQNApRLqWJQZg1lo1RMTXiWFNZ9k8z1dRUzi9ncnKcpsTKFBMdCk0Zw1S8EcgtAgQEUQTdXRL2xu6e3XN+f3zn/Xy/exYE2eWc727P+5+zrrvL9/l+Pp/n8zzv51aQyWRwOBwOh8Ph6MtI5PsBHA6Hw+FwOM423OBxOBwOh8PR5+EGj8PhcDgcjj4PN3gcDofD4XD0ebjB43A4HA6Ho8/DDR6Hw+FwOBx9HkWn+P+9vWa94DR+xmWMP04lY1+XD1zG3gCXse/LBy5jb8AJZXSGx+FwOBwOR5/HqRgeh6NbiDa2LCg4HcfC4XA4To3W1lYAUqkUAP369QOgqKjIdY3jhHCGx+FwOBwOR5+HMzw5QiaTob29HQg9EnkhhYWFFBUVdfpeb/VQxOg0NjYCcODAAQASiQRjx44FIJlMAr1XRofDkV80NjbyxBNPAHDw4EEAFi5cCMB5551n+tTR96A75kzuD2d4HA6Hw+Fw9Hn0iBksiyudTgPQ0dFBc3MzAHV1dQC89dZbANTX13P06FH7GmDYsGFMmjQJgDFjxgAwYMAAIGA/ehsymYyxODU1NQA8++yz5pHoXYwfPx4IPJPLL78cgKFDhwJQXFyc02fuKYjZeeyxxwC4++67ARgxYgR33nknABMmTAB679pGP4V0Om37XygsLIyljB0dHfapZ9Z+SyQSfZZ505lsbW2ltLQU6J178H8ZYskffPBBfvnLXwJh7s5FF10EBAxPb0T2PZpOpy1Pqa2trdMnhGe2pKTEPrWf48BwRfUMBM+uM9jU1ATA8ePHOXbsGIDZBbId6uvr7V3oe8lkknHjxgGhrTB8+HAg2Aen0l3O8DgcDofD4ejz6LYZmEqlzEJ7/fXXgYDNWLNmDQC7d+8G4L///a/9TiIR2Fmy1svLyxk2bBgAH/3oRwH44he/CMDFF19sbE92nkvcIAs9lUpZ7sry5csBePTRR3nnnXeA0IJ/9913AaiurubDH/5wrh+3x5FOp81yf/nllwF47bXXgMDKl/cR1/U7GbRPGxsbjbHTvtbnsWPH7BwMGTIEgCuvvJJp06YB0L9/fyDc+/mAPK0jR44AsHXrVmNZL7jgAiDYi8qx0nrpmQsKCnrd2kEo71133QXAvn37uOOOOwCYPHkyEH+mJ5PJmN7IzgXMZDLvyzhq3cUEFBcXGzsQPZO9YW11xh566CHefPNNAKqqqoDw3OXzjJ0KWgsxN4qA7N27l//85z9AcC71vX379gEhw6H1Ouecc5g7dy4AH/rQhwC45JJLLEKgd5HrfMkoKyXGpra2FgjyOXUfSNZjx46xf/9+AFpaWjp9lpeX29dRFuvSSy8F4JprrgECPQsh0/d+OGODRwesvb3dQjSPPPIIAE899ZQJrUTVK664AggU68iRI4FwEd555x1eeeUVADOU9DdvueUW5s+fDxD7C1OK6I033jC6dfXq1QA0NDSYkhGdrnfY1NRkVGVcZTsdpNNp2+SvvvoqEG7eYcOG2WGMs0KKQmsimdavX89f//pXALZs2QKEIcuOjg5bTx28Q4cOGd16/vnnA/lNStcFqbX59a9/bUb4tddeC8CiRYs455xzgHCfat8mk0n7urfs03Q6zb/+9S8A/vSnPwHBOV26dGk+H+u0oQvy+PHjvPfeewB2QWjtjh07ZntUP9PU1GS/qzWTUTtp0iQmTpwIwODBg4HgIokatnGDzpb27pYtW0zfSq+MGjUKiK9+yWQyZri89NJLQBjy37hxY5eQVklJCeXl5UAoU0VFBRDILENPP1NWVmbrKR2Uq7WMOvsy4uT0vvDCCwBs3rzZ9qzsg0wmY0RG1JiDgOCQPEJhYSEDBw7s9PMfRKfGc2c4HA6Hw+Fw9CC6HdKKWmiXXXYZEHgQSkJWgqrCUsXFxWaJySpsbW1l48aNAPz4xz8GQmagvb3dLPm4Qha5LNu7777bknaPHz8OQGVlJVOmTAFCek4/X1tba5avGLHCwsJYelonQpTt27NnDxCGNyXD9OnTLazTG5BKpWxNHnroISBIxJZcYj/kXQ0ZMsT2rLzs7du3s337diCk3fORjK/1EbUspuOFF17oxEZBkCio/SkvTLKOGDHCvKu4h5eF5uZmNm/eDITyV1RUnBb9nU9IpyhEvHPnTp5//nkA+1Q5dkNDgzEH0pWZTMbWRutXXV0NwIwZM7juuuuAMBxSWVnZKXE9ijissd7DihUrgEBmPZfSAbQ344oTRUMU4pkzZw6f/exngbCYZeTIkbZPT8T+aJ10FhOJRN7YLT1XfX29nbe1a9cC4V1QWVnJhRdeCAS6RJ+K+JSVlQEhOyWGEkKWsq2tjcrKSgD7vQ+y7s7wOBwOh8Ph6PM4Y4ZH1nVJSYnF3BRfLC0tNc83O+Yf9RZktSYSCUtqVoKhmKFRo0blPB75QSHv6i9/+Yt9KhlU8eXFixdbkllDQwOA5YPU1tYaMzJjxgwgZIF6A7SOzc3N/O1vfwPClgNKmps7d26vKLWXh/zuu+/y+9//HsA+6+rqLCdnwYIFALamQ4cONQbhwQcfBILkWHk3H/nIR4AweTmXDI88pb///e8APP7440DgNUuemTNnAkFOh7zp7DysmTNnWulv3PPp5HEePXrU2GPlZJWUlMS++aXyrZSYu2rVKlauXAnA22+/DYTynGh8S0FBgXn+Yur033v27DF9M3r0aCDYl/rd7HOa73eUTqctb+mf//wnEOzp7HL0uOvMVCplrJwKVsROfe973zNmJ7toIIp8r8XJoL24c+dOy2/UPac77aqrruLcc88FwnuxsLDQ9pv0jGTs6OiwdxHNL9O6n0k+YbdDWgUFBWbcSJkXFRWdlPKOHk4JuHbtWn7yk58AYQhImdcTJ06MrcGji0RJkffeey8QGG2ika+++moAli5dajSeKg0URnj66aftIEg5RRVQ3KH3cODAAUs61/ekUKdNmxZrefS8MlqWL1/OPffcA4RG+JgxY6y65xOf+ATQ+eCqB5HW8tChQ/Y97evsXj25gBJa77//fiBURMlkkk9/+tMAzJo1CwicFVUYrl+/HgiqRSA4f0p8Ff0cV2g9a2pqbE2lNBOJRKxDcplMxoxOGWurVq3ijTfeAEKjXDKUlpaajoxW1kle6WcZt9XV1fZ1tForO9Ug38m/UUdKOlZpABAaBpdccgmQ/+c9GSRHQ0ODnS2RBNdffz0QpDLozuhN3fazKz+3bdvGzp07ASytZc6cOQCMGzfOkpCjfYL0N7LXLxq266lK0XjuEIfD4XA4HI4eRLcZnkQiYV6CLLXo3KjsZKumpiZLBn344YeBwPMU23PzzTcD8JnPfAYIEp3iarmLllRpocIXhYWF1k/o1ltvBYJENFm1el+iMB977DFLXlN4TIlZcYbWVmv35JNPcvjwYSD0TsQgKNwZN2hfqrxcrM4999xjYVZ19Lztttss2VN9LqKeivZ8dGqzPJp8hVDS6bSFAXbs2AGE3tLEiRPNw5THn0qljGUUoyCvdPfu3fb/4gqtpxi12tpaW9to6WwcOtGeDOl02jzmZ555BoDDhw/b84tJF2NcXV3NoEGDgFB/NDc3G2OgzsNKWh4/frylDEjPlJSUxGaen+RUmOStt97iH//4BxDqGgh1igo94sqISC/s37/f+s+oiEEhno6ODgtjZicjQ/7X5GTQGin0um3bNmOUdb9pn0YLlqIJyYJCktEk7J5GPC0Jh8PhcDgcjh5Ej+TwyGqLzqpRDFreofIa1q1bZ1aurMKRI0eybNkyIGQE5LHEzaIVUqkUzz77LBB6YbJaJ0yYwHe+8x0AK8OLJtRJJlnHdXV1XWKhyn2JM7I7Ri9fvty8GTEb6pgdx062mUzGvJE//vGPnT5bW1utS/Ltt98OwLx588wjzpYnk8kY+7Fp0yYg2CN6D/lIVoaAUZV3LNZDZ2vZsmXWKiFa/qo1VOK5zvL+/fstJym7s29coGcXO7dnz54u+UapVCrWrS46OjpMbyrPr6WlxXSI8j+mT58OBPpTa6Sz2NzcbHtOe1C/N2bMGOtsLxaoqKgo70x6tL0FhLlmr7/+unUcjk7KFvMqtjVuiOYgQZALp0KAqVOnAuH9mEqlbA3FYkVzs7SHJXMymcz73ZhOp002scG1tbW2fpJDcg0aNKhL/lkikTCdmAvd6AyPw+FwOByOPo8eaTwoq00Z9Dt27DAv98UXXwRCC/Dtt9+2HBbFL2+55RYr81UToXxbr6dCXV0dDzzwABBasGoqt3jxYiuVlKzpdNpYHHku+mxpaenUhBDi60ELmUzGGINHH30UCLwVrZtGiWiybRzXs6Wlxao/oswOBOXmS5YsAeDjH/84EHgo2V6w1qmjo8OaiilXpqKiwhq7aW/k2os+fPiwtbEXVCI/c+ZMYw30XFGmKntCc21tra153PZndqM+MXf9+/c3GfUzLS0tnaZOxw3pdNrec/R9ywOW1y9Gfe/evaZLVLLe3t5u35PeEZszbty4E87Syiei94hYA+V67tq1y5hvPWdRUZHliMS1HF37TXJs2rTJKpgkq/bhyJEjjc1TztmRI0dMpyhfSfOjlixZYuNq8tXuI5PJ2PNHGVPtWelBMYtVVVVdmlsWFRXldO/1SOZeduLn3r172bVrFxAutqjwsrIyK5OUcbN+/Xqj6tSXQDRsvg9iNqTo//3vf5tRp+8peW7+/Pm2sLo82tvbTUHpPUkhFRUVmaJWl8rZs2fHNgwEgbKVEaty51QqZWur5HMl68YJkuGNN94wQ0eGpsrNb775Zi6++GKATh2i9bvZn01NTRbiVNuBuXPn2p7IdRm0zuTmzZtNkeqilMETnVOjvdnY2GhnVnsyGmJQmCsqfxzOqOTVp55v6NChljQpJRul4uOIgoICM5CV3JpMJm0d1MlbqQFtbW128Wgd0+m06RcVEugzmUzaZal/J1+IOgx6dq2N9u3evXtNdq1hSUmJtUiIw/47EbJDw4lEwkKJCvfIoBk6dKgVukjGmpoau0c1j0q69rnnnuM3v/kNEPYhykcivnSKyItRo0bZPtP9qJDjpEmT8j4I3ENaDofD4XA4+jx61CRUaev48eON4RBjE/W8ZPnKq37ppZdsXpESKjVT64YbbjAqNg7Qs69evdpoVlGqUUZAjJbo5La2NrOG9fOa7jtw4ECj4JV0mEqlYjXvJzuh8NChQ1aOL6ansLDQvA0l/EabmcXFE5M3vHbtWp5++mkgZDtmz54NBCXb2sOSub293WQQ+yZPbfPmzdZlWh7N7NmzjYrOdShLz7x169YurQ5UnhxtcKeQ6u7du615pDxT7eFod1shLmsq/SKWQHqkf//+5n0Kra2tdt7iiMLCQgsDKCS6c+dO0w3SLfosLCw0JjUaQtf6ab9rH6xdu5arrroKCBmkXCPK7OjZtAfFgKtVx9GjR40RkJyDBg2y/ZzN/hQUFJyQidVezdVZ1J7U/TVt2jRjf8V0TJ48GQjC5tIb0Qnp2WkQ6s7/05/+lKVLlwLBXQThbKlcQneZdMqVV17ZqWAAwrSWqqoq5s2bZ19DIGMudYgzPA6Hw+FwOPo8eoThkbcbbXQli08WuTzD0tJS+3l5Hnv27OEXv/gFAE888QQAX/3qV4GgjP3OO+8E4lGqLo9+w4YN5lnIWpcnWVxcbIlbQllZmeWC6Oflocmij34vLojm7EDIBDz88MM2EV7r2L9/f2sjLlmjoxSym2fleh0li3IgVq9ebV6vSnyV7xFN+pTs0URdeYnyYu68804bwfCpT30KCLy3fDW4i+YPZDf70gT3RCJh3rTyQWpqaqxdhPLPJHdJSUlsklyzkT0ZXPIXFxdb4rx0UWtrq7El2p9xypdLJBLmrYtxrK+vN09ZORJal379+hk7oPLl9vZ2S2AWky7dtX37dl5++WUgnFnYr1+/nK6p9qKe6eDBg8boqFRb+1DPB+H6FhcX2//XGYwyHNEmuBDsXb2bXDRYjDJKYo8nT55s4xbE/Go0TVlZ2fueLcmtQori4mK++93vAvDUU08BQd5hLvdxdF6b7uZzzz3XcgS1ttIxa9assT2pBq5jx47NaUFHj2hjPaguuWQyaS8+uxrgRBTW8OHDbfCmBhyq98mf//xnU1533XUXELzcfClcUZJSOtB185aWltrh0mcymTT6L6qMIaBspXhP1uclH0in0102rXq63HfffWY4aC1GjBhhIczsJMpov4XofJRcrqPesRTqgQMH7Flk6GQPsYVwDUtKSkyBKrH3D3/4AxDMU5ORf8MNNwD57RIenWWmy0IG3IoVK4Cgw7f2on6+oqLipN2UBw4caHs9bgZPNJkVOvdmufzyy4HwfB48eNAMnrhVm0Egi/acQsTpdNocI1W/KGRVVlZml726KkcNAvUJUyf4+vp6m5O2cOFC4MQViGcLmUym03BXCAbtKslVIXLp2sbGxi76JFokoH0dNXikR+WEnnfeeZ2MC+Cs9n+JyiijYMyYMbY/ZcB80H9bf2vOnDn29xXSuvHGG3OS/hGdnpA9G7CqqsqcXg0Nla7ct2+f7d2f//znQLA+mpupcyoD0TstOxwOh8PhcJwBeoThkbcn67WgoOCEU07f7/dldWuGlkoOv/nNb5oFq34oN910U84TemXVRsvMBckdZbj0dZSC1TuQVbxt2zYgSACWpS+KOV+9FaDzLBt5WaKNFcY6dOhQl9k+s2bNMo8qu5t0tFdGvlkPsXMtLS0W5tCaKMR19OjRLl1OS0pKjPlR6PW5554DAs9LXaXl2eRzDfX+L7zwQgvpyMOPMjiSUQn006dPt/cjWbVew4YNs3cRN4ZH5ye7DUImkzH51SLgzTffjHXSMoTyyNudNm2asRaXXnopQKe5dfo5yVhRUWEslhLT9fONjY3s378fCDvgjx49ulMX47OJ6N+PFkOITda+0/O2tbVZqF/6pLW11RgsnWuxtAMGDDBmTHs3yqTkgtWL9l2THigrK+vS9+pMMWjQIGMxdY+kUqmcMDyS6/jx41368CSTSSu9F6JsnsLpSr5ev349W7duBbCZf1/4wheA4C7U3dJTe9IZHofD4XA4HH0e3WZ4opasPgsLC884IUyWuGZQffvb37byu9/97ndA0BxOs6by5WmWlpZ2amQGnSf5ZifGZTIZiz/Lu/rtb38LBJayvNCPfexjQH5zeKITp+UBPvnkk0DQcBECWeW5iNG46aabunQ/jbIc+Z7VI7nEcBQUFHTpEh6dFSUPSl5TfX295Q3IQ1Fy+oIFC/j85z8PxCO5Xu//oosusvOjtRMLMmbMGGsfIO+4qKjIPC01O9Nerq6utjySuDE8QvZznaiJXzqdtvWOK7JZ88GDB9tZ0v4S49Pc3GwMj/Ri1NPXz0UZ5mzGJNe5TNJvaj577rnnWk6S9Kj05cGDB7s0liwoKLC/oRJ+5Q9OmDDBcpnEXJaXl9u+P5vTuPUeW1pajEWMdhfuqXNTUFBge1i5SWd7DbOn2B8+fNi+ll6orKzskrer30smk3YWxURu3bqVdevWAWExxQ9+8AMAFi1aZO0TtI7R/OAzeZfO8DgcDofD4ejzOGOGJ1quLC9XDE+0zPpMISvu/PPP71TNBIGHnmsPU/+echiqq6ut2kdZ6LJUx44dawyV3kVLS4uNjfi///s/ALZs2QIEHodyl/LNXEXR1NRkWfXKVVFlFoSexec+9zkgKLuUBf9+DFW+ytKzm9Mlk8kuLJ3iz1VVVeYRSuZVq1axcuVKIFzzuXPnAnDrrbfa2sWhwk5e7PDhw1m0aBEA119/PdA5JynbC2tra7NzHK2wg8DLyldL+O5A+kNeJdClLD3uKCoqMrZHaxBt2idGJ9poT3o5OnFd/09/I5p3mdMGcFmVvePGjTO2R+sknfPiiy+a7o82/pT+0Xypyy67DAgYn+xcs+g0+NPJKz1T6P03NDRY/mOU8e2pf3P79u32TnR3SOazhex5dQcOHLDvaTRUIpHo8n6jUY7o/QkBc6nfFaOs9gsrVqxg3759QNjqY8aMGd3K6+l2SKutrc0uBL2IqqqqLuWrp/tw2R19a2pqjOrM7u2TD+hCv+6666yMUopFJdu1tbU2F0WKaNOmTbzyyitAWOKtdzJr1iy+/OUvd/r5fCI6s0ediLMTBPv372+K5tprrwWCg53ddyZOnZZ1ENURvKqqypRS9uDCI0eOmEH7+OOPA0GissJhKqH81re+BcDUqVPzmqScjeiFcjoKInpO1bdFdHV0Xk4cjLkPCr0LJbJCuJ9lBMR1AGV0XfTudca0PkeOHDHdGy3PV2hyw4YNQChrUVGRGRUKB+U63Bw1RCDYp9nDUfXfTU1Ntl7StaWlpTYPTN2odXGWlpae8N7JpaPV3t5uISetzZAhQ7rtMOguvP322+0e/MY3vgHkbpaWnr25udmMaemMwsJC0696vuh71/0R7X8l/SQDVntx79699u601pMnT+402/CDwkNaDofD4XA4+jzO2CSMJuqqLG737t1A4EGrQ6g8CFntJ/MkoqVuEHpgv/rVr8xzVpMsWZD5gBiY+fPnG/shKk5M1/PPP2+0XHan4ujfUDjkhz/8oXlc+fSgs5913759FoZTcy8935QpU2wiutYjWnqfjXyzOxDuPYWeLrjgAgttiB4WC/fiiy9ayFFeTCKRMFbr61//OhCWCMedIThdtLW1Wfm6zmR2Am1vRbTlg1hWeeEKp8QVJ2r1IVZy//79to+1RvX19VbuK10qnT148GAuueQSIExozndBQWFhYRd2W/po+vTp1oVZDGt03lg2oxAtmslVqX32M7e2tpr+UHfh4uJiY6N0H57qufT31BD1+9//PhCwdnfccQcQMpdnW0Y9i+6A8vJym/auZpHPPPOMFa6IcVKrkqKiInvG6N7V+9m4cSMQskXFxcVMnToVCGUsLy/vlpzO8DgcDofD4ejz6HbQLzqZVhbta6+9xgMPPABgnsT8+fOBIN6a3Xyprq7OSrXFmsja2717t+WIqCFRPnMl9Mzjx4+39tj33nsvEJYq19XVWbw8OuNHpZJiRjSCoLq6Ola5EfIE6+rq7Gt5JMqjWrJkiXkr0cTHOEPvWLHiGTNmWENFsRrK12lpaTGGQzIvXLiQL33pS0DYNqG3yH4qRJNdtebZ4xoSiUQsRzGcLjR6YMCAAZarJfZDDGtc1zGawyP9p8+GhgZj2aNNNVV6LsZWBRRXXHFFl5l3+ZY7ymBJ1ygPdPLkyZa0qr2YyWSMSXg/tiRfxS0DBgwwBmrNmjVAME7h6quvBrAcT+mWKLulM1ZfX8+rr74KBNPRIYyifOUrX+G2224DcpfTqvXRvquoqLBWD7qva2pq7A5XfqRYuVQq1UV/FBQU2L7UOxCb88lPftKaDU+ZMgXo/sy3MzZ4JHx5ebkNRFu8eDEQdONVKERDCe+//34goLKyZyo1NjaaklVSsAS8/fbbufHGG4Gwgiafh1P/djKZtAv/Zz/7GYB12l23bp0ZcAqfzJo1y7pHq79L3C7LqGwQVD187WtfA0Lq/4orrgCCpF2FAfJNh58u9JyqFJgxY4YdSlXYad0A29cLFiwAgk7f6gcRt7XrLiRHIpGwni5SQLpQGhsbu8yB603yS7dMnTrVnDNVgUix5mvY6+kg+3wqHFVZWWmpAAqrK6EZwnCdwgPXXHONGXhxklfyaW/p2SZMmGDnTn3Kmpqa7D6QPo3DYNvowFANJJZRuXLlSpsHqUpdXfbt7e1dhvwqTAmhsf6jH/0ICCoutf65QvaA3nHjxtkzSNYDBw7YmdKnwnHvvfeera10TDKZND0r40/9lEaPHm1ntqc6VPeOm8rhcDgcDoejGyg4BUV9Wvx1dhfMlpaWLsnH+tywYYMlwKrErrKy0koKZe1NnjwZCFidbszNOh1Tv/dy9AFcxg8oX7R/iZgrJc4peXnQoEFG1+qztLT0bHVpjc0atrW12ew6hWzlQS9btox58+YBXUtOTwN5l1H6acWKFdx3330A3HLLLUDQZgK6HS4/qzJmz/NT4vUrr7zCI488AoShhePHjxuzMHHiRCAIEQDMmzfPwutnMLW7R89iDNFja6j1kr5paGgw1kY9hpSMvWPHDmMxxJpMmTLFin8UKVA4Ps779IPg/eyPbjJ1J/xlZ3gcDofD4XD0efQIwxNjxMaSPYtwGXtAvrPoaZwOYrOGmUzGGFjl4SkfZNKkSZaIeQb5ErGRsaWlhV27dgFhYmwPdcnOiYzZzEFTU5M1yVR58OHDh43hEZujz8rKyi5tQnpwHfu6rgGXsTfAGR6Hw+FwOBz/m3CGx2XsDXCvMg8yZs+Z6uYsoFjJKHZE6KG2EHmTUWslfZ5Op7uMUuihGVJ+Fl3G3oATyugGj8vYG+BK1mXsDXAZ+7584DL2BnhIy+FwOBwOx/8mTsXwOBwOh8PhcPR6OMPjcDgcDoejz8MNHofD4XA4HH0ebvA4HA6Hw+Ho83CDx+FwOBwOR5+HGzwOh8PhcDj6PNzgcTgcDofD0efx/3SPk8ase273AAAAAElFTkSuQmCC\n",
            "text/plain": [
              "<Figure size 720x72 with 10 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light",
            "tags": []
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "print('Randomly Generated Samples:')\n",
        "display_imgs(xtilde.sample())\n",
        "\n",
        "print('Randomly Generated Modes:')\n",
        "display_imgs(xtilde.mode())\n",
        "\n",
        "print('Randomly Generated Means:')\n",
        "display_imgs(xtilde.mean())"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [],
      "name": "Probabilistic_Layers_VAE.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
